<template>
  <div class="file-upload">
    <!-- 主图上传组件 -->
    <template v-if="uploadType === 'mainImage'">
      <el-upload
        class="avatar-uploader"
        :action="ossUploadHost"
        :data="ossUploadData"
        :show-file-list="false"
        :before-upload="beforeUpload"
        :on-success="handleSuccess">
        <template v-if="value">
          <div class="avatar-wrapper">
            <img :src="value" class="avatar">
            <span class="el-upload-list__item-status-label">
              <i class="el-icon-upload-success el-icon-check"></i>
            </span>
            <div class="avatar-actions">
              <i class="el-icon-zoom-in" @click.stop="handlePreview"></i>
              <i class="el-icon-delete" @click.stop="handleRemove"></i>
            </div>
          </div>
        </template>
        <i v-else class="el-icon-plus avatar-uploader-icon"></i>
      </el-upload>
    </template>

    <!-- 图片集上传组件 -->
    <template v-else-if="uploadType === 'imageList'">
      <el-upload
        :action="ossUploadHost"
        :http-request="ossUploadRequest"
        list-type="picture-card"
        :file-list="internalFileList"
        :on-preview="handlePreview"
        :on-remove="handleRemove"
        :before-upload="beforeUpload"
        :on-success="handleSuccess"
        multiple>
        <i class="el-icon-plus"></i>
      </el-upload>
      <el-dialog :visible.sync="dialogVisible">
        <img width="100%" :src="previewUrl" alt="">
      </el-dialog>
    </template>
  </div>
</template>

<script>
import request from '@/utils/request'

export default {
  name: 'FileUpload',
  props: {
    value: {
      type: [String, Array],
      default: ''
    },
    uploadType: {
      type: String,
      default: 'mainImage', // 'mainImage' | 'imageList'
      validator: value => ['mainImage', 'imageList'].includes(value)
    }
  },
  data() {
    return {
      ossUploadHost: '',
      ossUploadData: {},
      dialogVisible: false,
      previewUrl: '',
      internalFileList: []
    }
  },
  watch: {
    value: {
      handler(newVal) {
        if (this.uploadType === 'imageList' && Array.isArray(newVal)) {
          // 处理传入的是字符串数组还是对象数组的情况
          this.internalFileList = newVal.map(item => {
            // 如果是字符串，转换为对象
            if (typeof item === 'string') {
              return { 
                url: item, 
                name: item.substring(item.lastIndexOf('/') + 1) 
              };
            }
            // 如果已经是对象，直接返回
            return item;
          });
        }
      },
      immediate: true
    }
  },
  methods: {
    // 获取OSS上传签名参数
    async getOssPolicy() {
      try {
        const res = await request({
          url: '/api/oss/policy',
          method: 'get'
        });
        if (res.code === 0) {
          const data = res.data
          this.ossUploadHost = data.host
          this.ossUploadData = {
            OSSAccessKeyId: data.accessid,
            policy: data.policy,
            signature: data.signature,
            dir: data.dir,
            host: data.host,
            expire: data.expire
          }
        }
      } catch (error) {
        this.$message.error('获取上传配置失败')
      }
    },
    
    // 上传前处理
    async beforeUpload(file) {
      await this.getOssPolicy()
      
      const isImage = file.type.startsWith('image/')
      const isLt2M = file.size / 1024 / 1024 < 2
      
      if (!isImage) {
        this.$message.error('上传文件只能是图片格式!')
        return false
      }
      
      if (!isLt2M) {
        this.$message.error('上传图片大小不能超过 2MB!')
        return false
      }
      
      // 生成唯一文件名并设置上传key
      const suffix = file.name.substring(file.name.lastIndexOf('.'))
      const filename = Date.now() + '_' + Math.floor(Math.random() * 10000) + suffix
      this.ossUploadData.key = this.ossUploadData.dir + filename
      return true
    },
    
    // 自定义图片集上传请求，适配OSS直传
    ossUploadRequest(option) {
      const file = option.file
      const suffix = file.name.substring(file.name.lastIndexOf('.'))
      const filename = Date.now() + '_' + Math.floor(Math.random() * 10000) + suffix
      const key = this.ossUploadData.dir + filename
      const formData = new FormData()
      formData.append('key', key)
      formData.append('OSSAccessKeyId', this.ossUploadData.OSSAccessKeyId)
      formData.append('policy', this.ossUploadData.policy)
      formData.append('signature', this.ossUploadData.signature)
      formData.append('success_action_status', '200')
      formData.append('file', file)
      const xhr = new XMLHttpRequest()
      xhr.open('POST', this.ossUploadHost, true)
      xhr.onload = () => {
        if (xhr.status === 200) {
          file.url = this.ossUploadHost + '/' + key
          option.onSuccess({ key }, file)
        } else {
          option.onError(new Error('上传失败'))
        }
      }
      xhr.onerror = () => {
        option.onError(new Error('上传失败'))
      }
      xhr.send(formData)
    },
    
    // 上传成功回调
    handleSuccess(res, file, fileList) {
      if (this.uploadType === 'mainImage') {
        const imageUrl = this.ossUploadHost + '/' + this.ossUploadData.key
        this.$emit('input', imageUrl)
        this.$emit('success', res, file)
        this.$message.success('上传成功')
      } else if (this.uploadType === 'imageList') {
        if (file && res && res.key) {
          file.url = this.ossUploadHost + '/' + res.key
        }
        
        this.internalFileList = fileList.map(f => {
          if (f.response && f.response.key) {
            f.url = this.ossUploadHost + '/' + f.response.key
          }
          return f
        })
        
        // 发出对象数组而不是字符串数组，以保持与ProductEdit.vue中imageList的一致性
        this.$emit('input', this.internalFileList)
        this.$emit('success', res, file, fileList)
        this.$message.success('上传成功')
      }
    },
    
    // 预览图片
    handlePreview(file) {
      if (this.uploadType === 'mainImage') {
        this.previewUrl = this.value
        this.dialogVisible = true
      } else if (this.uploadType === 'imageList') {
        this.previewUrl = file.url
        this.dialogVisible = true
      }
    },
    
    // 删除图片
    handleRemove(file, fileList) {
      if (this.uploadType === 'mainImage') {
        this.$emit('input', '')
        this.$emit('remove', file)
      } else if (this.uploadType === 'imageList') {
        this.internalFileList = fileList
        // 发出对象数组而不是字符串数组，以保持与ProductEdit.vue中imageList的一致性
        this.$emit('input', fileList)
        this.$emit('remove', file, fileList)
      }
    }
  }
}
</script>

<style scoped>
.avatar-uploader {
  width: 148px;
  height: 148px;
  border: 1px dashed #d9d9d9;
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
}

.avatar-uploader:hover {
  border-color: #409EFF;
}

.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 148px;
  height: 148px;
  line-height: 148px;
  text-align: center;
}

.avatar {
  width: 148px;
  height: 148px;
  display: block;
}

.avatar-wrapper {
  position: relative;
  display: inline-block;
}

.avatar-actions {
  display: none;
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.4);
  color: #fff;
  align-items: center;
  justify-content: center;
  z-index: 2;
  font-size: 22px;
}

.avatar-wrapper:hover .avatar-actions {
  display: flex;
}

.avatar-actions i {
  margin: 0 8px;
  cursor: pointer;
  transition: color 0.2s;
}

.avatar-actions i:hover {
  color: #409EFF;
}

.avatar-wrapper .el-upload-list__item-status-label {
  position: absolute;
  right: 0;
  top: 0;
  width: 32px;
  height: 32px;
  z-index: 10;
  pointer-events: none;
  background: transparent;
  display: flex;
  align-items: flex-start;
  justify-content: flex-end;
  padding: 0;
}

.avatar-wrapper .el-upload-list__item-status-label:after {
  content: '';
  position: absolute;
  right: 0;
  top: 0;
  width: 0;
  height: 0;
  border-top: 32px solid #13ce66;
  border-left: 32px solid transparent;
  z-index: 10;
}

.avatar-wrapper .el-upload-list__item-status-label .el-icon-upload-success {
  position: absolute;
  right: 2px;
  top: 2px;
  font-size: 14px;
  color: #fff;
  z-index: 11;
  transform: rotate(-0deg);
  font-weight: normal;
  pointer-events: none;
}

.avatar-wrapper:hover .el-upload-list__item-status-label {
  display: none !important;
}
</style>